Add acpi_table_disable() into xen/drivers/acpi/tables.c
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 30 Jul 2007 10:27:48 +0000 (11:27 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Mon, 30 Jul 2007 10:27:48 +0000 (11:27 +0100)
This function can disable a ACPI table by updating the table header.

Signed-off-by: Akio Takebe <takebe_akio@jp.fujitsu.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/acpi/boot.c
xen/drivers/acpi/tables.c
xen/include/xen/acpi.h

index be16765afb6d057f4705ee1b3fae28604ad7de20..85aa49414f9c083b6942f392cbc1be5413092a58 100644 (file)
@@ -371,12 +371,19 @@ extern u32 pmtmr_ioport;
 
 #ifdef CONFIG_ACPI_SLEEP
 /* Get pm1x_cnt and pm1x_evt information for ACPI sleep */
-static int __init
+static void __init
 acpi_fadt_parse_sleep_info(struct fadt_descriptor_rev2 *fadt)
 {
+       struct acpi_table_rsdp *rsdp;
+       unsigned long rsdp_phys;
        struct facs_descriptor_rev2 *facs = NULL;
        uint64_t facs_pa;
 
+       rsdp_phys = acpi_find_rsdp();
+       if (!rsdp_phys || acpi_disabled)
+               goto bad;
+       rsdp = __va(rsdp_phys);
+
        if (fadt->revision >= FADT2_REVISION_ID) {
                /* Sanity check on FADT Rev. 2 */
                if ((fadt->xpm1a_cnt_blk.address_space_id !=
@@ -432,8 +439,7 @@ acpi_fadt_parse_sleep_info(struct fadt_descriptor_rev2 *fadt)
                        "FACS is shorter than ACPI spec allow: 0x%x",
                        facs->length);
 
-       if ((acpi_rsdp_rev < 2) ||
-           (facs->length < 32)) {
+       if ((rsdp->revision < 2) || (facs->length < 32)) {
                acpi_sinfo.wakeup_vector = facs_pa + 
                        offsetof(struct facs_descriptor_rev2,
                                 firmware_waking_vector);
@@ -451,10 +457,9 @@ acpi_fadt_parse_sleep_info(struct fadt_descriptor_rev2 *fadt)
                acpi_sinfo.pm1a_cnt, acpi_sinfo.pm1b_cnt,
                acpi_sinfo.pm1a_evt, acpi_sinfo.pm1b_cnt,
                acpi_sinfo.wakeup_vector, acpi_sinfo.vector_width);
-       return 0;
+       return;
 bad:
        memset(&acpi_sinfo, 0, sizeof(acpi_sinfo));
-       return 0;
 }
 #endif
 
index 075c9fb8519ac948224da0e5eae1cada0d7ac2a5..dc7e7e8845965ca8833d9897f78a539748cfd5ff 100644 (file)
@@ -73,7 +73,6 @@ struct acpi_table_sdt {
 
 static unsigned long sdt_pa;   /* Physical Address */
 static unsigned long sdt_count;        /* Table count */
-unsigned char acpi_rsdp_rev;
 
 static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
 
@@ -610,8 +609,6 @@ int __init acpi_table_init(void)
               "RSDP (v%3.3d %6.6s                                ) @ 0x%p\n",
               rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
 
-       acpi_rsdp_rev = rsdp->revision;
-
        if (rsdp->revision < 2)
                result =
                    acpi_table_compute_checksum(rsdp,
@@ -634,3 +631,143 @@ int __init acpi_table_init(void)
 
        return 0;
 }
+
+int __init
+acpi_table_disable(enum acpi_table_id table_id)
+{
+       struct acpi_table_header *header = NULL;
+       struct acpi_table_rsdp *rsdp;
+       unsigned long rsdp_phys;
+       char *table_name;
+       int id;
+
+       rsdp_phys = acpi_find_rsdp();
+       if (!rsdp_phys)
+               return -ENODEV;
+
+       rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
+               sizeof(struct acpi_table_rsdp));
+       if (!rsdp)
+               return -ENODEV;
+
+       for (id = 0; id < sdt_count; id++)
+               if (sdt_entry[id].id == table_id)
+                       break;
+
+       if (id == sdt_count)
+               return -ENOENT;
+
+       table_name = acpi_table_signatures[table_id];
+
+       /* First check XSDT (but only on ACPI 2.0-compatible systems) */
+
+       if ((rsdp->revision >= 2) &&
+           (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
+
+               struct acpi_table_xsdt *mapped_xsdt = NULL;
+
+               sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
+
+               /* map in just the header */
+               header = (struct acpi_table_header *)
+                   __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
+
+               if (!header) {
+                       printk(KERN_WARNING PREFIX
+                              "Unable to map XSDT header\n");
+                       return -ENODEV;
+               }
+
+               /* remap in the entire table before processing */
+               mapped_xsdt = (struct acpi_table_xsdt *)
+                   __acpi_map_table(sdt_pa, header->length);
+               if (!mapped_xsdt) {
+                       printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
+                       return -ENODEV;
+               }
+               header = &mapped_xsdt->header;
+
+               if (strncmp(header->signature, "XSDT", 4)) {
+                       printk(KERN_WARNING PREFIX
+                              "XSDT signature incorrect\n");
+                       return -ENODEV;
+               }
+
+               if (acpi_table_compute_checksum(header, header->length)) {
+                       printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
+                       return -ENODEV;
+               }
+
+               if (id < sdt_count) {
+                       header = (struct acpi_table_header *)
+                          __acpi_map_table(mapped_xsdt->entry[id], sizeof(struct acpi_table_header));
+               } else {
+                       printk(KERN_WARNING PREFIX
+                              "Unable to disable entry %d\n",
+                              id);
+                       return -ENODEV;
+               }
+       }
+
+       /* Then check RSDT */
+
+       else if (rsdp->rsdt_address) {
+
+               struct acpi_table_rsdt *mapped_rsdt = NULL;
+
+               sdt_pa = rsdp->rsdt_address;
+
+               /* map in just the header */
+               header = (struct acpi_table_header *)
+                   __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
+               if (!header) {
+                       printk(KERN_WARNING PREFIX
+                              "Unable to map RSDT header\n");
+                       return -ENODEV;
+               }
+
+               /* remap in the entire table before processing */
+               mapped_rsdt = (struct acpi_table_rsdt *)
+                   __acpi_map_table(sdt_pa, header->length);
+               if (!mapped_rsdt) {
+                       printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
+                       return -ENODEV;
+               }
+               header = &mapped_rsdt->header;
+
+               if (strncmp(header->signature, "RSDT", 4)) {
+                       printk(KERN_WARNING PREFIX
+                              "RSDT signature incorrect\n");
+                       return -ENODEV;
+               }
+
+               if (acpi_table_compute_checksum(header, header->length)) {
+                       printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
+                       return -ENODEV;
+               }
+               if (id < sdt_count) {
+                       header = (struct acpi_table_header *)
+                          __acpi_map_table(mapped_rsdt->entry[id], sizeof(struct acpi_table_header));
+               } else {
+                       printk(KERN_WARNING PREFIX
+                              "Unable to disable entry %d\n",
+                              id);
+                       return -ENODEV;
+               }
+       }
+
+       else {
+               printk(KERN_WARNING PREFIX
+                      "No System Description Table (RSDT/XSDT) specified in RSDP\n");
+               return -ENODEV;
+       }
+
+       memcpy(header->signature, "OEMx", 4);
+       memcpy(header->oem_id, "xxxxxx", 6);
+       memcpy(header->oem_id+1, table_name, 4);
+       memcpy(header->oem_table_id, "Xen     ", 8);
+       header->checksum = 0;
+       header->checksum = generate_acpi_checksum(header, header->length);
+
+       return 0;
+}
index 062e4d4b40892842d0abc3b5fa5a115c77216802..aa7a36aba46f9f3a4a9e9cd9f028b33beb5712cc 100644 (file)
@@ -383,6 +383,7 @@ int acpi_boot_table_init (void);
 int acpi_numa_init (void);
 
 int acpi_table_init (void);
+int acpi_table_disable(enum acpi_table_id table_id);
 int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
 int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
 int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
@@ -535,6 +536,5 @@ static inline int acpi_get_pxm(acpi_handle handle)
 #endif
 
 extern int pnpacpi_disabled;
-extern unsigned char acpi_rsdp_rev;
 
 #endif /*_LINUX_ACPI_H*/